/**
*******************************************************
*@file  protect.c
*@brief protect.c
*@author 花满楼
*@date     2020-06-17
*@version  V1
*@attention none
*******************************************************
*/
#include "protect.h"
#include "math.h"
#include "stdlib.h"
#include "timer.h"
#include "stdlib.h"
#include "rs485.h"
#include "bq79616.h"
#include "fan.h"
#include "can.h"
#include "relay_ctl.h"


_Alarm_RegisterGroup Alarm_Reg; //根据维谛项目，设置的故障寄存器

u32 cell_ovp_count = 0, cell_uvp_count = 0, cell_ova_count = 0, cell_uva_count = 0; //电芯过欠压保护、告警计数器
u32 cell_ot_count = 0, cell_ut_count = 0; //电芯过欠压、过欠温计数器

u32 bat_ovp_count = 0, bat_uvp_count = 0, bat_ova_count = 0, bat_uva_count = 0; //系统过欠压保护、告警计数器

u32 dischar_otp_count = 0, dischar_utp_count = 0, dischar_ota_count = 0, dischar_uta_count = 0; //放电过温、放电低温保护
u32 char_otp_count = 0, char_utp_count = 0, char_ota_count = 0, char_uta_count = 0; //充电过温、充电低温保护

u32 dvp_count = 0, dva_count = 0, dtp_count = 0, dta_count = 0; //压差过大、温差过大的保护和告警

u32 char_ocp_count = 0, char_oca_count = 0, dischar_ocp_count = 0, dischar_oca_count = 0; //系统充放电过流保护、告警计数器
u32 char_ocp_start_count = 0, char_oca_start_count = 0, dischar_ocp_start_count = 0, dischar_oca_start_count = 0; //充放电故障、保护的起始时间
u8  char_ocp_num = 0, char_oca_num = 0, dischar_ocp_num = 0, dischar_oca_num = 0; //充电放电的故障、告警的次数记录


/**
*******************************************************
*@brief 根据单点进行限值保护，当前包括电芯过压、欠压、过温、低温，机柜过压、欠压、充电过流、放电过流
*@param[in]   *Protect_Cur:系统保护电流值
*@param[in]   load_vol:负载电压的值
*@param[in]   *cell_temper:系统中电芯的温度值，偏移-40C
*@return  cell_maxi.cell_tem_max:   pack中的最高温度
*@note    none
*******************************************************
*/
u16 Singel_Protect(s16 *Protect_Cur, s16 load_vol,u16* cell_temper)
{
    Pack_Mes_Tol.Pack_Alm = NO_FAULT;   //初始化无故障
    cell_maxi_reg  cell_maxi;
    cell_maxi.cell_vol_max = Get_Max_Vol();
    cell_maxi.cell_vol_min = Get_Min_Vol();
    cell_maxi.cell_tem_max = Get_Max_Tem(cell_temper);
    cell_maxi.cell_tem_min = Get_Min_Tem(cell_temper);
    Protect_Moudle(&cell_maxi);       //模组本身故障判断，过压、欠压、过温、低温、均衡等
    Protect_Sys_V();                            //系统本身的电压故障判断，保护过压、欠压
    Protect_Sys_I(Protect_Cur);        //系统本身的电压故障判断，保护充电过流、放电过流
    Protect_Sys_T(&cell_maxi);        //系统本身的温度故障判断，保护充放电过温、低温
    Protect_SOH();
    Protect_DV_DT(&cell_maxi);        //对压差和温差的保护
    Calcu_Total_V();        //从电芯电压累计出模组总压，并与系统总压进行比较，如果差距超过20V，则认为系统电压异常

    /*****************风扇控制失效保护*******************/
    if (FAN_EN != FAN_STATUS)
        Alarm_Reg.Slight_Alarm1.Bit.Other_Alarm = 1;    //风扇故障暂定义为其他故障
    else
        Alarm_Reg.Slight_Alarm1.Bit.Other_Alarm = 0;

    /***************外部±母线反接*****************/
    if ((0 - load_vol) > FAIL_CONNECT_TH)   //负载电压＜-94V，放大10倍
        Alarm_Reg.Serious_Alarm2.Bit.Bat_Connect_Err = 1;
    else
        Alarm_Reg.Serious_Alarm2.Bit.Bat_Connect_Err = 0;   //负载动力电缆反接保护

    /***************接触器失效保护***************/
    if ((RELAY_CHARGE != STATUS_CHARGE) || (RELAY_DISCHAR != STATUS_DISCHAR) || (RELAY_PRECHAR != STATUS_PRECHAR))
        Alarm_Reg.Serious_Alarm2.Bit.Relay_Fail = 1;    //继电器失效

//      else
//          Alarm_Reg.Serious_Alarm2.Bit.Relay_Fail = 0;    //继电器释放
    /******************磁保持继电器控制命令*******************/
    Latch_RLY_CTL(Pack_Mes_Tol.Pack_Vol, cell_maxi.cell_vol_min,load_vol);
    return cell_maxi.cell_tem_max;
}

/**
*******************************************************
*@brief 检测电芯电压中的最大值
*@param   none，其实应该是所有电压信号，考虑传输复杂度，采用全局变量
*@return  vol_max：电芯最大电压
*@note    函数耦合性太高，后期需要重点优化
*******************************************************
*/
u16 Get_Max_Vol()
{
    u16 i, j;
    u16 vol_max = 0; //0mV

    for (i = 0; i < BQ79616_NUM; i++)
    {
        for (j = 0; j < CELLNUM_P_DEV; j++)
        {
			if((i*16+j)<CELL_NUM)
			{
				if (vol_max < Bq79616_Reg[i].VCELL[j].Word)
				{
					vol_max = Bq79616_Reg[i].VCELL[j].Word;
					CELL_Vol_Maxi.Max_Cell_Volt = Bq79616_Reg[i].VCELL[j].Word;
					CELL_Vol_Maxi.Max_Volt_No = i * CELLNUM_P_DEV + j;
				}			
			}
        }
    }

    return vol_max;
}

/**
*******************************************************
*@brief 检测电芯电压中的最小值
*@param   none，其实应该是所有电压信号，考虑传输复杂度，采用全局变量
*@return  vol_min：电芯最小电压
*@note    函数耦合性太高，后期需要重点优化
*******************************************************
*/
u16 Get_Min_Vol()
{
    u16 i, j;
    u16 vol_min = 5000; //5000mV

    for (i = 0; i < CELLNUM_P_DEV; i++)
    {
        for (j = 0; j < BQ79616_NUM; j++)
        {
			if((i*16+j)<CELL_NUM)
			{
				if (vol_min > Bq79616_Reg[i].VCELL[j].Word)
				{
					vol_min = Bq79616_Reg[i].VCELL[j].Word;
					CELL_Vol_Maxi.Min_Cell_Volt = Bq79616_Reg[i].VCELL[j].Word;
					CELL_Vol_Maxi.Min_Volt_No = i * CELLNUM_P_DEV + j;
				}			
			}
        }
    }

    return vol_min;
}

/**
*******************************************************
*@brief 检测电芯温度中的最大值
*@param   *cell_temper:温度值数组
*@return  tem_max：电芯最大电压
*@note    函数耦合性太高，后期需要重点优化
*******************************************************
*/
u16 Get_Max_Tem(u16 *cell_temper)
{
    u16 i;
    u16 tem_max = 0; //0 ，偏移量是-40℃，
	
	cell_temper[0] = cell_temper[1];//第一路没接，用第二路做统一比较
    for (i = 0; i < CELLNUM_P_TEM*BQ79616_NUM; i++)
    {
		if (tem_max < cell_temper[i])
		{
			tem_max = cell_temper[i];
			Pack_Tem_Maxi.Max_Cell_Tem = cell_temper[i];
			Pack_Tem_Maxi.Max_Tem_No = i;
		}
    }

    return tem_max;
}

/**
*******************************************************
*@brief 检测电芯温度中的最小值
*@param   *cell_temper:温度值数组
*@return  tem_min：电芯最小电压
*@note    函数耦合性太高，后期需要重点优化
*******************************************************
*/
u16 Get_Min_Tem(u16 *cell_temper)
{
    u16 i;
    u16 tem_min = 240;  //200℃，-40℃的便宜

	cell_temper[0] = cell_temper[1];//第一路没接，用第二路做统一比较
    for (i = 0; i < CELLNUM_P_TEM*BQ79616_NUM; i++)
    {
		if (tem_min > cell_temper[i])
		{
			tem_min =cell_temper[i];
			Pack_Tem_Maxi.Min_Cell_Tem = cell_temper[i];
			Pack_Tem_Maxi.Min_Tem_No = i;
		}
    }

    return tem_min;
}
/**
*******************************************************
*@brief 电芯的过压、欠压等保护，一旦出现严重故障，马上切断继电器（但不在此处切断），其余暂时忽略
*@param[in]   *sys_maxi；系统中电压和温度的最大、最小值
*@return  none
*@note    故障信号、个别需要切断继电器
*******************************************************
*/
void Protect_Moudle(cell_maxi_reg *sys_maxi)
{
    /***********************************严重故障保护************************************/
    /******电芯过压保护******/
    if (sys_maxi->cell_vol_max >= (u16)Cell_OVP_Th)
    {
        if (0 == cell_ovp_count) //保证仅赋值1次
            cell_ovp_count = timer_count;

        if ((timer_count - cell_ovp_count) > TIME_COUNT_2S) //1年内计时满2s
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_OV = 1;   //电芯过压保护
            Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
        }
    }

    /******电芯过压保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_OV)
    {
        if (sys_maxi->cell_vol_max < Cell_OVPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_OV = 0;   //保护清零
            cell_ovp_count = 0; //计时清零，为下一次做准备
        }
    }

    /******电芯欠压保护******/
    if (sys_maxi->cell_vol_min <= (u16)Cell_UVP_Th)
    {
        if (0 == cell_uvp_count) //保证仅赋值1次
            cell_uvp_count = timer_count;

        if ((timer_count - cell_uvp_count) > TIME_COUNT_2S) //1年内计时满2s
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_UV = 1;   //电芯过压保护
            Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
        }
    }

    /******电芯欠压保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_UV)
    {
        if (sys_maxi->cell_vol_min > Cell_OVARecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_UV = 0;
            cell_uvp_count = 0;
        }
    }

    /**********************************电芯采集失效告警**************************************/
    if (sys_maxi->cell_vol_min < CELL_VOL_LOSE)
        Alarm_Reg.Serious_Alarm1.Bit.Cell_Fail = 1;
    else
        Alarm_Reg.Serious_Alarm1.Bit.Cell_Fail = 0;

    /**********************************轻微故障告警******************************************/
    /******电芯过压告警******/
    if (sys_maxi->cell_vol_max >= (u16)Cell_OVA_Th)
    {
        if (0 == cell_ova_count) //保证仅赋值1次
            cell_ova_count = timer_count;

        if ((timer_count - cell_ova_count) > TIME_COUNT_2S) //1年内计时满2s
        {
            Alarm_Reg.Slight_Alarm1.Bit.Cell_OV = 1;    //电芯过压告警

            if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
        }
    }

    /******电芯过压告警释放******/
    if (0 != Alarm_Reg.Slight_Alarm1.Bit.Cell_OV)
    {
        if (sys_maxi->cell_vol_max < Cell_OVARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Cell_OV = 0;    //保护清零
            cell_ova_count = 0; //计时清零，为下一次做准备
        }
    }

    /******电芯欠压告警******/
    if (sys_maxi->cell_vol_min <= (u16)Cell_UVA_Th)
    {
        if (0 == cell_uva_count) //保证仅赋值1次
            cell_uva_count = timer_count;

        if ((timer_count - cell_uva_count) > TIME_COUNT_2S) //1年内计时满2s
        {
            Alarm_Reg.Slight_Alarm1.Bit.Cell_UV = 1;    //电芯过压告警

            if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
        }
    }

    /******电芯欠压保护释放******/
    if (0 != Alarm_Reg.Slight_Alarm1.Bit.Cell_UV)
    {
        if (sys_maxi->cell_vol_min > Cell_OVARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Cell_UV = 0;
            cell_uva_count = 0;
        }
    }
	
/************************BQ79616的电芯电压保护************************************/
	/******电芯过压告警******/
	if(0!=(Bq79616_Reg[0].FAULT_OV1 | Bq79616_Reg[1].FAULT_OV1 | Bq79616_Reg[2].FAULT_OV1 | Bq79616_Reg[3].FAULT_OV1 |  \
		Bq79616_Reg[0].FAULT_OV2 | Bq79616_Reg[1].FAULT_OV2 | Bq79616_Reg[2].FAULT_OV2 | Bq79616_Reg[3].FAULT_OV2))
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_OV = 1;
	}
	else
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_OV = 0;
	}
	
	/******电芯欠压告警******/
	if(0!=(Bq79616_Reg[0].FAULT_UV1 | Bq79616_Reg[1].FAULT_UV1 | Bq79616_Reg[2].FAULT_UV1 | Bq79616_Reg[3].FAULT_UV1 |  \
		Bq79616_Reg[0].FAULT_UV2 | Bq79616_Reg[1].FAULT_UV2 | Bq79616_Reg[2].FAULT_UV2 | Bq79616_Reg[3].FAULT_UV2))
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_UV = 1;
	}
	else
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_UV = 0;
	}
	
	/******电芯过温告警******/
	if(0!=(Bq79616_Reg[0].FAULT_OT | Bq79616_Reg[1].FAULT_OT | Bq79616_Reg[2].FAULT_OT | Bq79616_Reg[3].FAULT_OT))
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_OT = 1;
	}
	else
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_OT = 0;
	}
	/******电芯VC采集开路告警******/
	if(0!=(Bq79616_Reg[0].FAULT_COMP_VCOW1 | Bq79616_Reg[1].FAULT_COMP_VCOW1 | Bq79616_Reg[2].FAULT_COMP_VCOW1 | Bq79616_Reg[3].FAULT_COMP_VCOW1 |  \
	Bq79616_Reg[0].FAULT_COMP_VCOW2 | Bq79616_Reg[1].FAULT_COMP_VCOW2 | Bq79616_Reg[2].FAULT_COMP_VCOW2 | Bq79616_Reg[3].FAULT_COMP_VCOW2))
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_VC_Open = 1;
	}
	else
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_VC_Open = 0;
	}
	/******电芯VC-CB采集误差过大告警******/
	if(0!=(Bq79616_Reg[0].FAULT_COMP_VCCB1 | Bq79616_Reg[1].FAULT_COMP_VCCB1 | Bq79616_Reg[2].FAULT_COMP_VCCB1 | Bq79616_Reg[3].FAULT_COMP_VCCB1 |  \
	Bq79616_Reg[0].FAULT_COMP_VCCB2 | Bq79616_Reg[1].FAULT_COMP_VCCB2 | Bq79616_Reg[2].FAULT_COMP_VCCB2 | Bq79616_Reg[3].FAULT_COMP_VCCB2))
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_VCCB_Fail = 1;
	}
	else
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_VCCB_Fail = 0;
	}
	
	/******电芯均衡失效告警******/
	if(0!=(Bq79616_Reg[0].FAULT_COMP_CBFET1 | Bq79616_Reg[1].FAULT_COMP_CBFET1 | Bq79616_Reg[2].FAULT_COMP_CBFET1 | Bq79616_Reg[3].FAULT_COMP_CBFET1 |  \
	Bq79616_Reg[0].FAULT_COMP_CBFET2 | Bq79616_Reg[1].FAULT_COMP_CBFET2 | Bq79616_Reg[2].FAULT_COMP_CBFET2 | Bq79616_Reg[3].FAULT_COMP_CBFET2))
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_Balan_Fail = 1;
	}
	else
	{
		Alarm_Reg.Serious_Alarm2.Bit.Bq_Balan_Fail = 0;
	}
}

/**
*******************************************************
*@brief 总压过压、欠压判断，置位告警信号，一旦出现严重，切断继电器
*@param   none
*@return  none
*@note    故障信号、个别需要切断继电器
*******************************************************
*/
void Protect_Sys_V()
{
    u32 bat_vol;    //临时变量，暂时不清楚系统总压怎么采集

    /***********************************严重故障保护************************************/
    /******系统过压保护******/
    if (bat_vol >= Bat_OVP_Th)
    {
        if (0 == bat_ovp_count) //保证仅赋值1次
            bat_ovp_count = timer_count;

        if ((timer_count - bat_ovp_count) > TIME_COUNT_2S) //1年内计时满2s
        {
            Alarm_Reg.Serious_Alarm1.Bit.Bat_OV = 1;    //系统过压保护
            Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
        }
    }

    /******系统过压保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Bat_OV)
    {
        if (bat_vol < Bat_OVPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Bat_OV = 0;    //保护清零
            bat_ovp_count = 0;  //计时清零，为下一次做准备
        }
    }

    /******系统欠压保护******/
    if (bat_vol <= Bat_UVP_Th)
    {
        if (0 == bat_uvp_count) //保证仅赋值1次
            bat_uvp_count = timer_count;

        if ((timer_count - bat_uvp_count) > TIME_COUNT_2S) //1年内计时满2s
        {
            Alarm_Reg.Serious_Alarm1.Bit.Bat_UV = 1;    //系统过压保护
            Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
        }
    }

    /******系统欠压保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Bat_UV)
    {
        if (bat_vol > Bat_UVPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Bat_UV = 0;
            bat_uvp_count = 0;
        }
    }

    /**********************************轻微故障告警******************************************/
    /******系统过压告警******/
    if (bat_vol >= Bat_UVA_Th)
    {
        if (0 == bat_ova_count) //保证仅赋值1次
            bat_ova_count = timer_count;

        if ((timer_count - bat_ova_count) > TIME_COUNT_2S) //1年内计时满2s
        {
            Alarm_Reg.Slight_Alarm1.Bit.Bat_OV = 1; //系统过压告警

            if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
        }
    }

    /******系统过压告警释放******/
    if (0 != Alarm_Reg.Slight_Alarm1.Bit.Bat_OV)
    {
        if (bat_vol < Bat_OVARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Bat_OV = 0; //保护清零
            bat_ova_count = 0;  //计时清零，为下一次做准备
        }
    }

    /******系统欠压告警******/
    if (bat_vol <= Bat_UVA_Th)
    {
        if (0 == bat_uva_count) //保证仅赋值1次
            bat_uva_count = timer_count;

        if ((timer_count - bat_uva_count) > TIME_COUNT_2S) //1年内计时满2s
        {
            Alarm_Reg.Slight_Alarm1.Bit.Bat_UV = 1; //系统过压告警

            if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
        }
    }

    /******系统欠压告警释放******/
    if (0 != Alarm_Reg.Slight_Alarm1.Bit.Bat_UV)
    {
        if (bat_vol > Cell_UVARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Bat_UV = 0;
            bat_uva_count = 0;
        }
    }
}

/**
*******************************************************
*@brief 充、放电过流判断，置位告警信号，一旦出现严重故障，切断继电器
*@param[in]    *Protect_Cur:系统保护电流值，充电为正，放电为负
*@return  none
*@note    需要注意一次过流信号会出现几次char_ocp_num和dischar_ocp_num能增加几次
*******************************************************
*/

void Protect_Sys_I(s16 *Protect_Cur)
{
    // u32 bat_cur;    //临时变量，暂时不清楚系统总压怎么采集

    /***********************************严重故障保护************************************/
    /******系统充电过流保护******/
    if (*Protect_Cur >= Cell_Char_OCP_Th)
    {
        if (0 == char_ocp_count) //保证仅赋值1次
        {
            char_ocp_count = timer_count;   //用于恢复的计数
            char_ocp_num++;
        }

        if (0 == char_ocp_start_count)
            char_ocp_start_count = timer_count; //用于不恢复的计数

        if ((timer_count - char_ocp_count) > TIME_COUNT_5S) //1年内计时满2s
        {
            Alarm_Reg.Serious_Alarm1.Bit.Char_OC = 1;   //充电过流保护
            Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
        }
    }

    /******系统充电过流保护释放******/
    if ((char_ocp_num < 10) && ((timer_count - char_ocp_start_count) > (u32)TIME_COUNT_3HOUR))
    {
        char_ocp_num = 0;
        char_ocp_start_count = 0;
    }

    if ((0 != Alarm_Reg.Serious_Alarm1.Bit.Char_OC) && (char_ocp_num < 10))
    {
        if ((timer_count - char_ocp_count) > TIME_COUNT_1MIN) //1年内计时满1min
        {
            Alarm_Reg.Serious_Alarm1.Bit.Char_OC = 0;   //保护清零
            char_ocp_count = 0; //计时清零，为下一次做准备
        }
    }

    /******系统放电过流保护******/
    if (*Protect_Cur >= Cell_Dischar_OCP_Th)
    {
        if (0 == dischar_ocp_count) //保证仅赋值1次
		{
			dischar_ocp_count = timer_count;
			dischar_ocp_num++;
		}

        if ((timer_count - dischar_ocp_count) > TIME_COUNT_5S) //1年内计时满2s
        {
            Alarm_Reg.Serious_Alarm1.Bit.Dischar_OC = 1;    //放电过流保护
            Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
        }
    }

    /******系统放电保护释放******/
    if ((dischar_ocp_num < 10) && ((timer_count - dischar_ocp_start_count) > (u32)TIME_COUNT_3HOUR))
    {
        dischar_ocp_num = 0;
        dischar_ocp_start_count = 0;
    }

    if ((0 != Alarm_Reg.Serious_Alarm1.Bit.Dischar_OC) && (dischar_ocp_num < 10))
    {
        if ((timer_count - dischar_ocp_count) > TIME_COUNT_1MIN) //1年内计时满1min
        {
            Alarm_Reg.Serious_Alarm1.Bit.Dischar_OC = 0;
            dischar_ocp_count = 0;
        }
    }

    /**********************************轻微故障告警******************************************/
    /******系统充电过流告警******/
    if (*Protect_Cur >= Cell_Char_OCA_Th)
    {
        if (0 == char_oca_count) //保证仅赋值1次
            char_oca_count = timer_count;

        if ((timer_count - char_oca_count) > TIME_COUNT_5S) //1年内计时满2s
        {
            Alarm_Reg.Slight_Alarm1.Bit.Char_OC = 1;    //充电过流告警

            if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
        }

    }

    /******系统充电过流告警释放******/
    if ((char_oca_num < 10) && ((timer_count - char_oca_start_count) > (u32)TIME_COUNT_3HOUR))
    {
        char_oca_num = 0;
        char_oca_start_count = 0;
    }

    if ((0 != Alarm_Reg.Slight_Alarm1.Bit.Char_OC) && (char_oca_num < 10))
    {
        if ((timer_count - char_oca_count) > TIME_COUNT_1MIN) //1年内计时满1min
        {
            Alarm_Reg.Slight_Alarm1.Bit.Char_OC = 0;    //保护清零
            char_oca_count = 0; //计时清零，为下一次做准备
        }
    }

    /******系统放电过流告警******/
    if (*Protect_Cur >= Cell_Dischar_OCA_Th)
    {
        if (0 == dischar_oca_count) //保证仅赋值1次
            dischar_oca_count = timer_count;

        if ((timer_count - dischar_oca_count) > TIME_COUNT_5S) //1年内计时满2s
        {
            Alarm_Reg.Slight_Alarm1.Bit.Dischar_OC = 1; //放电过流告警

            if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
        }
    }

    /******系统放电过流告警释放******/
    if ((dischar_oca_num < 10) && ((timer_count - dischar_oca_start_count) > (u32)TIME_COUNT_3HOUR))
    {
        dischar_oca_num = 0;
        dischar_oca_start_count = 0;
    }

    if ((0 != Alarm_Reg.Slight_Alarm1.Bit.Dischar_OC) && (dischar_oca_num < 10))
    {
        if ((timer_count - dischar_oca_count) > TIME_COUNT_1MIN) //1年内计时满2s
        {
            Alarm_Reg.Slight_Alarm1.Bit.Dischar_OC = 0;
            dischar_oca_count = 0;
        }
    }
}

/**
*******************************************************
*@brief 充放电过程中过温、低温判断，置位告警信号，一旦出现严重，切断继电器
*@param[in]   sys_maxi:系统中电压和温度的最值
*@return  none
*@note    *放电过温、低温单独检测；充电过温和低温与静止、故障作为一种状态检测
                    *系统中暂时未定义系统状态变量，暂时定义临时变量替代
*******************************************************
*/
void Protect_Sys_T(cell_maxi_reg *sys_maxi)
{
    u8 sys_state = 0;   //系统暂时未定义系统状态变量，暂时定义临时变量替代

    /***********************************放电状态的保护和告警************************************/
    if (1 == sys_state) //放电状态
    {
        /******系统放电过温保护******/
        if (sys_maxi->cell_tem_max >= Dischar_OTP_Th)
        {
            if (0 == dischar_otp_count) //保证仅赋值1次
                dischar_otp_count = timer_count;

            if ((timer_count - dischar_otp_count) > TIME_COUNT_2S) //1年内计时满2s
            {
                Alarm_Reg.Serious_Alarm1.Bit.Cell_OT = 1;   //系统放电过温保护
                Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
            }
        }

        /******系统放电低温保护******/
        if (sys_maxi->cell_tem_min <= Dischar_UTP_Th)
        {
            if (0 == dischar_utp_count) //保证仅赋值1次
                dischar_utp_count = timer_count;

            if ((timer_count - dischar_utp_count) > TIME_COUNT_2S) //1年内计时满2s
            {
                Alarm_Reg.Serious_Alarm1.Bit.Cell_UT = 1;   //系统放电低温保护
                Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
            }
        }

        /******系统放电过温告警******/
        if (sys_maxi->cell_tem_max >= Dischar_OTA_Th)
        {
            if (0 == dischar_ota_count) //保证仅赋值1次
                dischar_ota_count = timer_count;

            if ((timer_count - dischar_ota_count) > TIME_COUNT_2S) //1年内计时满2s
            {
                Alarm_Reg.Slight_Alarm1.Bit.Cell_OT = 1;    //系统放电过温告警

                if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                    Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
            }
 
        }

        /******系统放电低温告警******/
        if (sys_maxi->cell_tem_min <= Dischar_UTA_Th)
        {
            if (0 == dischar_uta_count) //保证仅赋值1次
                dischar_uta_count = timer_count;

            if ((timer_count - dischar_uta_count) > TIME_COUNT_2S) //1年内计时满2s
            {
                Alarm_Reg.Slight_Alarm1.Bit.Cell_UT = 1;    //系统放电低温告警

                if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                    Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
            }
        }
    }
    /*******************************************************充电或其它状态保护、告警**************************************************************************/
    else
    {
        /******************系统充电过温保护*******************/
        if (sys_maxi->cell_tem_max >= Charge_OTP_Th)
        {
            if (0 == char_otp_count) //保证仅赋值1次
                char_otp_count = timer_count;

            if ((timer_count - char_otp_count) > TIME_COUNT_2S) //1年内计时满2s
            {
                Alarm_Reg.Serious_Alarm1.Bit.Cell_OT = 1;   //系统充电过温保护
                Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
            }
        }

        /******系统充电低温保护******/
        if (sys_maxi->cell_tem_min <= Charge_OTP_Th)
        {
            if (0 == char_utp_count) //保证仅赋值1次
                char_utp_count = timer_count;

            if ((timer_count - char_utp_count) > TIME_COUNT_2S) //1年内计时满2s
            {
                Alarm_Reg.Serious_Alarm1.Bit.Cell_UT = 1;   //系统充电低温保护
                Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
            }
        }

        /******************系统充电过温告警*******************/
        if (sys_maxi->cell_tem_max >= Charge_OTA_Th)
        {
            if (0 == char_ota_count) //保证仅赋值1次
                char_ota_count = timer_count;

            if ((timer_count - char_ota_count) > TIME_COUNT_2S) //1年内计时满2s
            {
                Alarm_Reg.Slight_Alarm1.Bit.Cell_OT = 1;    //系统充电过温告警

                if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                    Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
            }
        }

        /******系统充电低温告警******/
        if (sys_maxi->cell_tem_min <= Charge_UTA_Th)
        {
            if (0 == char_uta_count) //保证仅赋值1次
                char_uta_count = timer_count;

            if ((timer_count - char_uta_count) > TIME_COUNT_2S) //1年内计时满2s
            {
                Alarm_Reg.Slight_Alarm1.Bit.Cell_UT = 1;    //系统充电低温告警

                if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                    Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
            }
        }
    }

    /******系统放电过温保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_OT)
    {
        if (sys_maxi->cell_tem_max < Dischar_OTPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_OT = 0;   //保护清零
            dischar_otp_count = 0;  //计时清零，为下一次做准备
        }
    }

    /******系统放电低温保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_UT)
    {
        if (sys_maxi->cell_tem_min > Dischar_UTPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_UT = 0;
            dischar_utp_count = 0;
        }
    }

    /******系统放电过温告警释放******/
    if (0 != Alarm_Reg.Slight_Alarm1.Bit.Cell_OT)
    {
        if (sys_maxi->cell_tem_max < Dischar_OTARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Cell_OT = 0;    //保护清零
            dischar_ota_count = 0;  //计时清零，为下一次做准备
        }
    }

    /******系统放电低温告警释放******/
    if (0 != Alarm_Reg.Slight_Alarm1.Bit.Cell_UT)
    {
        if (sys_maxi->cell_tem_min > Dischar_UTARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Cell_UT = 0;
            dischar_uta_count = 0;
        }
    }

    /****************************************充电故障保护与告警释放************************************************************/

    /******系统充电过温保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_OT)
    {
        if (sys_maxi->cell_tem_max < Charge_OTPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_OT = 0;   //保护清零
            char_otp_count = 0; //计时清零，为下一次做准备
        }
    }

    /******系统充电低温保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_UT)
    {
        if (sys_maxi->cell_tem_min > Charge_OTPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_UT = 0;
            char_utp_count = 0;
        }
    }

    /******系统充电过温告警释放******/
    if (0 != Alarm_Reg.Slight_Alarm1.Bit.Cell_OT)
    {
        if (sys_maxi->cell_tem_max < Charge_OTARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Cell_OT = 0;    //保护清零
            char_ota_count = 0; //计时清零，为下一次做准备
        }
    }

    /******系统充电低温告警释放******/
    if (0 != Alarm_Reg.Slight_Alarm1.Bit.Cell_UT)
    {
        if (sys_maxi->cell_tem_min > Charge_OTARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Cell_UT = 0;
            char_uta_count = 0;
        }
    }

    /***********************************温度检测失效的故障保护************************************/
    if ((sys_maxi->cell_tem_max > Cell_TEMH_LOSE) || (sys_maxi->cell_vol_min < Cell_TEML_LOSE))
        Alarm_Reg.Serious_Alarm1.Bit.Tem_Sam_Fail = 1;      //温度检测失效
    else
        Alarm_Reg.Serious_Alarm1.Bit.Tem_Sam_Fail = 0;
}


/**
*******************************************************
*@brief SOH小于1，认为寿命结束
*@param   none
*@return  none
*@note    故障信号、个别需要切断接触器
*******************************************************
*/
void Protect_SOH()
{
}

/**
*******************************************************
*@brief   根据各个电芯的电压，计算整体电压
*@param   none
*@return  none
*@note    故障信号、个别需要切断继电器
*******************************************************
*/
void Calcu_Total_V()
{
}

/**
*******************************************************
*@brief   根据各个电芯压差、温差情况判断整体的压差多大、温差过大
*@param[in]    *sys_maxi：系统中电芯电压和温度最值
*@return  none
*@note    none
*******************************************************
*/
void Protect_DV_DT(cell_maxi_reg *sys_maxi)
{
    /***********************************************系统压差过大保护*******************************************************/
    /******系统电芯压差过大保护******/
    if ((sys_maxi->cell_vol_max - sys_maxi->cell_vol_min) >= DVP_Th)
    {
        if (0 == dvp_count) //保证仅赋值1次
            dvp_count = timer_count;

        if ((timer_count - dvp_count) > TIME_COUNT_5S) //1年内计时满2s
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_Dif_Vol = 1;    //系统压差过大保护
            Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
        }
    }

    /******系统电芯压差过大保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_Dif_Vol)
    {
        if ((sys_maxi->cell_vol_max - sys_maxi->cell_vol_min) < DVPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm1.Bit.Cell_Dif_Vol = 0;
            dvp_count = 0;
        }
    }

    /******系统电芯压差过大告警******/
    if ((sys_maxi->cell_vol_max - sys_maxi->cell_vol_min) >= DVA_Th)
    {
        if (0 == dva_count) //保证仅赋值1次
            dva_count = timer_count;

        if ((timer_count - dva_count) > TIME_COUNT_5S) //1年内计时满2s
        {
            Alarm_Reg.Slight_Alarm1.Bit.Dif_Vol = 1;    //系统压差过大告警

            if (Pack_Mes_Tol.Pack_Alm < SERIOUS_FAULT)
                Pack_Mes_Tol.Pack_Alm = SLIGHT_FAULT;
        }
    }

    /******系统电芯压差过大告警释放******/
    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_Dif_Vol)
    {
        if ((sys_maxi->cell_vol_max - sys_maxi->cell_vol_min) < DVARecover_Th)
        {
            Alarm_Reg.Slight_Alarm1.Bit.Dif_Vol = 0;
            dva_count = 0;
        }
    }

    /*************************************************系统温差过大保护****************************************************************/
    /******系统电芯温差过大保护******/
    if ((sys_maxi->cell_tem_max - sys_maxi->cell_tem_min) >= DTP_Th)
    {
        if (0 == dtp_count) //保证仅赋值1次
            dtp_count = timer_count;

        if ((timer_count - dtp_count) > TIME_COUNT_5S) //1年内计时满2s
        {
            Alarm_Reg.Serious_Alarm2.Bit.Cell_Dif_Temp = 1;    //系统温差过大保护
            Pack_Mes_Tol.Pack_Alm = SERIOUS_FAULT;
        }
    }

    /******系统电芯温差过大保护释放******/
    if (0 != Alarm_Reg.Serious_Alarm2.Bit.Cell_Dif_Temp)
    {
        if ((sys_maxi->cell_tem_max - sys_maxi->cell_tem_min) < DTPRecover_Th)
        {
            Alarm_Reg.Serious_Alarm2.Bit.Cell_Dif_Temp = 0;
            dtp_count = 0;
        }
    }

    /****************************************维谛的通讯协议中没有温差过大告警设置，暂时屏蔽***************************************************/
//      /******系统电芯温差过大告警******/
//    if ((sys_maxi->cell_tem_max - sys_maxi->cell_tem_min) >= DTA_Th)
//    {
//        if (0 == dta_count) //保证仅赋值1次
//            dta_count = timer_count;
//        if ((timer_count > dta_count) && ((timer_count - dta_count) > TIME_COUNT_5S)) //1年内计时满2s
//        {
//            Alarm_Reg.Slight_Alarm1.Bit.Dif_Vol = 1;    //系统温差过大告警
//        }
//        else
//            if ((timer_count < dta_count) || ((TIME_COUNT_YEAR - dta_count + timer_count) > TIME_COUNT_5S)) //在计数满1年的跨接处
//            {
//                Alarm_Reg.Slight_Alarm1.Bit.Dif_Vol = 1;    //系统温差过大告警
//            }
//    }
//    /******系统电芯温差过大告警释放******/
//    if (0 != Alarm_Reg.Serious_Alarm1.Bit.Cell_Dif_Vol)
//    {
//        if ((sys_maxi->cell_tem_max - sys_maxi->cell_tem_min) < DTARecover_Th)
//        {
//            Alarm_Reg.Slight_Alarm1.Bit.Dif_Vol = 0;
//            dta_count = 0;
//        }
//    }
}
